#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
性能优化工具集
包含GPU内存管理、性能监控、自适应优化等功能
"""

import time
import threading
import psutil
import pynvml
import numpy as np
from collections import deque
import logging

try:
    pynvml.nvmlInit()
    HAS_NVML = True
except:
    HAS_NVML = False

logger = logging.getLogger(__name__)

class PerformanceMonitor:
    """实时性能监控器"""
    
    def __init__(self, window_size=30):
        self.window_size = window_size
        self.metrics = {
            'fps': deque(maxlen=window_size),
            'processing_time': deque(maxlen=window_size),
            'gpu_utilization': deque(maxlen=window_size),
            'memory_usage': deque(maxlen=window_size),
            'cpu_utilization': deque(maxlen=window_size)
        }
        self.start_time = time.time()
        self.frame_count = 0
        self.running = False
        self.monitor_thread = None
        
    def start_monitoring(self):
        """启动性能监控"""
        self.running = True
        self.monitor_thread = threading.Thread(target=self._monitor_loop)
        self.monitor_thread.daemon = True
        self.monitor_thread.start()
        
    def stop_monitoring(self):
        """停止性能监控"""
        self.running = False
        if self.monitor_thread:
            self.monitor_thread.join()
    
    def update_frame_metrics(self, processing_time_ms):
        """更新帧处理指标"""
        self.frame_count += 1
        current_time = time.time()
        
        # 计算FPS
        if self.frame_count > 1:
            fps = 1.0 / (current_time - self.start_time) * self.frame_count
            self.metrics['fps'].append(fps)
        
        # 处理时间
        self.metrics['processing_time'].append(processing_time_ms)
        
        # 更新开始时间
        if self.frame_count % self.window_size == 0:
            self.start_time = current_time
            self.frame_count = 0
    
    def _monitor_loop(self):
        """监控循环"""
        while self.running:
            if HAS_NVML:
                try:
                    handle = pynvml.nvmlDeviceGetHandleByIndex(0)
                    
                    # GPU利用率
                    gpu_util = pynvml.nvmlDeviceGetUtilizationRates(handle).gpu
                    self.metrics['gpu_utilization'].append(gpu_util)
                    
                    # 显存使用
                    mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
                    mem_usage = (mem_info.used / mem_info.total) * 100
                    self.metrics['memory_usage'].append(mem_usage)
                    
                except pynvml.NVMLError:
                    pass
            
            # CPU利用率
            cpu_util = psutil.cpu_percent(interval=0.1)
            self.metrics['cpu_utilization'].append(cpu_util)
            
            time.sleep(0.1)
    
    def get_performance_summary(self):
        """获取性能摘要"""
        summary = {}
        for key, values in self.metrics.items():
            if values:
                summary[key] = {
                    'current': values[-1] if values else 0,
                    'average': np.mean(values),
                    'min': np.min(values),
                    'max': np.max(values),
                    'std': np.std(values)
                }
            else:
                summary[key] = {'current': 0, 'average': 0, 'min': 0, 'max': 0, 'std': 0}
        
        return summary
    
    def print_performance_report(self):
        """打印性能报告"""
        summary = self.get_performance_summary()
        
        print("\n" + "="*50)
        print("📊 性能报告")
        print("="*50)
        
        if 'fps' in summary:
            fps = summary['fps']
            print(f"🎯 FPS: {fps['current']:.1f} (avg: {fps['average']:.1f}, min: {fps['min']:.1f})")
        
        if 'processing_time' in summary:
            proc = summary['processing_time']
            print(f"⏱️  处理时间: {proc['current']:.1f}ms (avg: {proc['average']:.1f}ms)")
        
        if HAS_NVML and 'gpu_utilization' in summary:
            gpu = summary['gpu_utilization']
            print(f"⚡ GPU利用率: {gpu['current']:.1f}% (avg: {gpu['average']:.1f}%)")
        
        if 'memory_usage' in summary:
            mem = summary['memory_usage']
            print(f"💾 显存使用: {mem['current']:.1f}% (avg: {mem['average']:.1f}%)")
        
        if 'cpu_utilization' in summary:
            cpu = summary['cpu_utilization']
            print(f"🖥️  CPU利用率: {cpu['current']:.1f}% (avg: {cpu['average']:.1f}%)")
        
        print("="*50)

class AdaptiveOptimizer:
    """自适应优化器"""
    
    def __init__(self, performance_monitor):
        self.monitor = performance_monitor
        self.optimization_level = 'balanced'  # 'performance', 'balanced', 'quality'
        self.frame_skip_threshold = 10.0  # ms
        self.confidence_threshold = 0.25
        self.nms_threshold = 0.45
        self.target_fps = 60
        
        # 优化策略
        self.strategies = {
            'performance': {
                'conf_thres': 0.5,
                'nms_thres': 0.3,
                'max_det': 50,
                'frame_skip': 2,
                'model_size': 'n'
            },
            'balanced': {
                'conf_thres': 0.25,
                'nms_thres': 0.45,
                'max_det': 100,
                'frame_skip': 1,
                'model_size': 'n'
            },
            'quality': {
                'conf_thres': 0.1,
                'nms_thres': 0.6,
                'max_det': 1000,
                'frame_skip': 0,
                'model_size': 's'
            }
        }
    
    def should_skip_frame(self, processing_time):
        """是否应该跳过帧"""
        return processing_time > self.frame_skip_threshold
    
    def adjust_thresholds(self, current_fps):
        """根据性能调整阈值"""
        if current_fps < self.target_fps * 0.7:
            # 性能不足，降低质量
            self.optimization_level = 'performance'
            logger.info("⚡ 切换到性能模式")
        elif current_fps > self.target_fps * 1.2:
            # 性能充足，提高质量
            self.optimization_level = 'quality'
            logger.info("🎯 切换到质量模式")
        else:
            # 性能平衡
            self.optimization_level = 'balanced'
            logger.info("⚖️  切换到平衡模式")
        
        return self.strategies[self.optimization_level]
    
    def get_optimal_params(self):
        """获取优化参数"""
        return self.strategies[self.optimization_level]

class SmartFrameSkipper:
    """智能帧跳过策略"""
    
    def __init__(self, stable_threshold=5, motion_threshold=50):
        self.stable_threshold = stable_threshold
        self.motion_threshold = motion_threshold
        self.frame_count = 0
        self.skip_counter = 0
        self.target_stability = {}  # 目标ID -> 稳定计数器
        self.previous_positions = {}
        
    def should_skip_detection(self, tracked_targets):
        """是否应该跳过检测"""
        if not tracked_targets:
            return False
        
        # 检查目标稳定性
        stable_targets = 0
        for target in tracked_targets:
            target_id = getattr(target, 'id', 0)
            current_pos = getattr(target, 'position', [0, 0])
            
            if target_id in self.previous_positions:
                prev_pos = self.previous_positions[target_id]
                distance = np.linalg.norm(np.array(current_pos) - np.array(prev_pos))
                
                if distance < self.motion_threshold:
                    self.target_stability[target_id] = self.target_stability.get(target_id, 0) + 1
                    if self.target_stability[target_id] >= self.stable_threshold:
                        stable_targets += 1
                else:
                    self.target_stability[target_id] = 0
            
            self.previous_positions[target_id] = current_pos
        
        # 如果所有目标都稳定，可以跳过检测
        return stable_targets == len(tracked_targets)
    
    def update_skip_strategy(self, processing_time, fps):
        """更新跳过策略"""
        if processing_time > 20:  # 处理时间超过20ms
            self.skip_counter = min(self.skip_counter + 1, 3)
        elif fps > 50:
            self.skip_counter = max(self.skip_counter - 1, 0)
        
        return max(0, self.skip_counter)

class MemoryProfiler:
    """内存分析器"""
    
    def __init__(self):
        self.memory_snapshots = deque(maxlen=100)
        
    def snapshot(self, label=""):
        """创建内存快照"""
        snapshot = {
            'timestamp': time.time(),
            'label': label,
            'cpu_memory': psutil.virtual_memory().percent,
            'gpu_memory': 0
        }
        
        if HAS_NVML:
            try:
                handle = pynvml.nvmlDeviceGetHandleByIndex(0)
                mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
                snapshot['gpu_memory'] = (mem_info.used / 1024**3)  # GB
            except:
                pass
        
        self.memory_snapshots.append(snapshot)
        return snapshot
    
    def get_memory_trend(self):
        """获取内存使用趋势"""
        if not self.memory_snapshots:
            return None
        
        cpu_trend = [s['cpu_memory'] for s in self.memory_snapshots]
        gpu_trend = [s['gpu_memory'] for s in self.memory_snapshots]
        
        return {
            'cpu_trend': np.gradient(cpu_trend) if len(cpu_trend) > 1 else [0],
            'gpu_trend': np.gradient(gpu_trend) if len(gpu_trend) > 1 else [0],
            'cpu_avg': np.mean(cpu_trend),
            'gpu_avg': np.mean(gpu_trend)
        }

# 全局性能监控实例
performance_monitor = PerformanceMonitor()

# 装饰器用于性能监控
def monitor_performance(func):
    """性能监控装饰器"""
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        processing_time = (time.time() - start_time) * 1000
        
        if hasattr(performance_monitor, 'update_frame_metrics'):
            performance_monitor.update_frame_metrics(processing_time)
        
        return result
    return wrapper

if __name__ == "__main__":
    # 测试性能监控
    monitor = PerformanceMonitor()
    monitor.start_monitoring()
    
    try:
        time.sleep(2)
        for i in range(10):
            monitor.update_frame_metrics(15 + i)
            time.sleep(0.1)
        
        monitor.print_performance_report()
    finally:
        monitor.stop_monitoring()